/**
 * 
 * Copyright 2009, 2010 Mike Jamer [email: mikejamer@gmail.com ]
 * 
 * This File is part of Moose IRC
 * 
 * MooseIRC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * MooseIRC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MooseIRC.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

using System;
using System.Collections.Generic;
using moose.extension;

namespace moose.irc
{

	/// <summary>
	/// IRC Action, executes bits of code, in response to triggers, or 
	/// as extensions to other actions 
	/// </summary>
	[CLSCompliant(true)]
	public abstract class IrcAction : object
	{

		/// <summary>
		/// A really basic, linear hierarchy,
		/// this enables overriding actions, and enables an override to invoke the base
		/// action
		/// </summary>
		internal LinkedList<IrcAction> m_llObjectHierarchy;
		
		/// <summary>
		/// Initialize IrcAction 
		/// </summary>
		public IrcAction() : base() {
			initialize(this);
			return;
		}
		
		/// <summary>
		/// No need to build hierarchy nessecarily 
		/// </summary>
		/// <param name="owner">
		/// A <see cref="IrcAction"/>
		/// </param>
		public IrcAction(IrcAction owner) : base() {
			initialize(owner);
			return;
		}
		
		private void initialize(IrcAction owner) {
			if (owner.m_llObjectHierarchy == null) //This will either be the root
				owner.m_llObjectHierarchy = new LinkedList<IrcAction>();
			else //or an extension
				m_llObjectHierarchy = owner.m_llObjectHierarchy;
			
			m_llObjectHierarchy.AddLast(this);
			
			if (owner == this) //This is root, lets build the object hierarchy
				build_object_hierarchy();
			
			return;
		}
		
		/// <summary>
		/// Returns valid Session States for action to execute 
		/// </summary>
		/// <returns>
		/// A <see cref="IrcSessionStates"/>,
		/// bitwise stacked value, indicating all possible states for this action 
		/// to execute.
		/// Any other current state, will throw an exception instead.
		/// </returns>
		public abstract IrcSessionStates valid_states();
		
		/// <summary>
		/// must override this, 
		/// this is the actual action, whatever the command / response is supposed to do...
		/// </summary>
		/// <param name="session">
		/// A <see cref="IrcSession"/>
		/// </param>
		/// <param name="message">
		/// A <see cref="IrcMessage"/>
		/// </param>
		public abstract void action(IrcSession session, IrcMessage message);
		
		/// <summary>
		/// Execute the base Action Logic 
		/// </summary>
		/// <param name="session">
		/// A <see cref="IrcSession"/>
		/// </param>
		/// <param name="message">
		/// A <see cref="IrcMessage"/>
		/// </param>
		protected void base_action(IrcSession session, IrcMessage message) {
			//If this is the parent, there is nothing to invoke.  We will short circuit quietly, no need to make a fuss
			if (m_llObjectHierarchy.First.Value == this) return;
			m_llObjectHierarchy.Find(this).Previous.Value.action(session, message);
			return;
		}
		
		/// <summary>
		/// Execute IRC Action 
		/// </summary>
		/// <param name="session">
		/// A <see cref="IrcSession"/>
		/// </param>
		/// <param name="message">
		/// A <see cref="IrcMessage"/>
		/// </param>
		public void execute(IrcSession session, IrcMessage message) {
			IrcAction action = m_llObjectHierarchy.Last.Value;
			if ((action.valid_states() & session.SessionState) != session.SessionState)
				return; //Will not execute in case of incorrect session state
			action.action(session, message);
 			return;
		}
		
		/// <summary>
		/// Builds Object Heirarchy 
		/// </summary>
		private void build_object_hierarchy() {
			
			IrcAction extension = ExtensionManager.get_extension(this.GetType(), this);
			while (extension != null) {
                extension = ExtensionManager.get_extension(extension.GetType(), extension);
			}
			
			return;
		}
		
	}
}
